import { getLngLat, isSameLngLat } from '../js/AMapUtils.js';
import { AMapGeoCode } from '../js/AMapGeoCode.js';
import { debounce } from 'lodash-es';

export default {
  name: 'AMapPositionPicker',
  emits: ['update:modelValue', 'change'],
  props: {
    /* value: { position: { lng: "lng", lat: "lat" }, address: "" } */
    modelValue: { type: Object, default: () => ({}) },
    mapGetter: { type: Function, default: undefined },
    markerOptions: { type: [Object, Function], default: undefined },
    enableGeocode: { type: Boolean, default: false },
    replaceFields: { type: Object, default: () => ({}) },
  },
  computed: {
    fields() {
      const dft = { position: 'position', address: 'address' };
      return Object.assign(dft, this.replaceFields);
    },
  },
  created() {
    if (typeof this.mapGetter === 'function') {
      this.map = this.mapGetter();
    } else {
      throw new Error('mapGetter is not a function, please provide a function to return a map instance');
    }
    this.$watch(
      () => this.modelValue,
      debounce(function (value = {}) {
        this.setMarkerByValue(value);
      }, 500),
      { immediate: true, deep: true }
    );
    this.startListener();
  },
  unmounted() {
    this.stopListener();
    if (this.marker) {
      this.marker.setMap(null);
    }
  },
  methods: {
    setMarkerByValue(value) {
      const { fields } = this;
      const position = getLngLat(value[fields.position]);
      this.address = value[fields.address];
      if (position && !isSameLngLat(position, this.position)) {
        this.position = position;
        this.addMarker(position);
        this.geoCode({ position }).then(({ address }) => {
          this.address = address;
          this.onChange({ position: this.position, address: this.address });
        });
      }
    },
    startListener() {
      if (this.map) {
        this.map.on('click', this.onMapClick, this);
      } else {
        console.warn('map is not ready');
      }
    },
    stopListener() {
      if (this.map) {
        this.map.off('click', this.onMapClick, this);
      } else {
        console.warn('map is not ready');
      }
    },
    onChange({ position, address }) {
      const { fields } = this;
      const data = { [fields.position]: position, [fields.address]: address };
      this.$emit('update:modelValue', data);
      this.$emit('change', data);
    },
    async onMapClick({ lnglat }) {
      const res = await this.geoCode({ position: lnglat });
      this.onChange({ ...res, position: lnglat });
    },
    async geoCode({ position, address }) {
      if (!this.enableGeocode || (!position && !address)) return {};
      if (!this.aMapGeoCode) {
        this.aMapGeoCode = new AMapGeoCode();
      }
      if (position) {
        return { address: await this.aMapGeoCode.regeocode(position) };
      }
      if (address) {
        return { position: await this.aMapGeoCode.geocode(address) };
      }
    },
    addMarker(position) {
      position = getLngLat(position);
      if (!this.marker) {
        this.marker = new AMap.Marker(this.getMarkerOption());
        this.marker.setMap(this.map);
      }
      if (position) {
        this.marker.setPosition(position);
        this.map.setFitView(this.marker);
      }
    },
    getMarkerOption() {
      return Object.assign({}, typeof this.markerOptions === 'function' ? this.markerOptions() : this.markerOptions);
    },
  },
  render() {
    return null;
  },
};
